<?php

/**
 * MODULE NAME   : codecrafter.php
 *
 * DESCRIPTION   : CodeCrafter Source Code Generator module controller
 *
 * MODIFICATION HISTORY
 *   V0.1   26/07/2006   - Pradesh     - Created
 *   V0.2   01/09/2006   - Pradesh
 *          - User interface changes
 *          - Overwrite functionality
 *   V1.0   15/12/2006   - Pradesh
 *          - User interface changes
 *          - Active Record Option
 *          - Verbose Code Option
 *          - Persistence Model fields
 *          - Field customisation.
 *
 * @package             codecrafter
 * @author              Pradesh Chanderpaul - DataCraft Software
 * @copyright           Copyright (c) 2006, DataCraft Software
 * @license             http://www.datacraft.co.za/codecrafter/license.html
 * @link                http://www.datacraft.co.za/codecrafter/
 * @version             Version 1.0
 */

class Codecrafter extends Controller {

// General Options
var $clobber;           // Option to overwrite existing directories.
var $path_separator;
var $suffix;
var $output_base;

var $controllers_dir;
var $models_dir;
var $views_dir;

// Code gneration options -> detirmines how code will look,
var $xss_filter_mode;
var $persistence_mode;
var $verbose_mode;
var $grid_type;         // Pagination
var $use_activerecord;
var $tag_type;

   function Codecrafter() {
      parent::Controller();

      define ("CONTROLLER_TEMPLATE",         APPPATH."/views/templates/controller.src");
      define ("TRANSITIONAL_AR_CONTROLLER_TEMPLATE",         APPPATH."/views/templates/controller_myactiverecord_transition.src");

      define ("MODEL_TEMPLATE",              APPPATH."/views/templates/model.src");
      define ("ACTIVERECORD_MODEL_TEMPLATE", APPPATH."/views/templates/model_activerecord.src");
      define ("TRANSITIONAL_AR_MODEL_TEMPLATE", APPPATH."/views/templates/model_myactiverecord_transition.src");


      define ("DETAILS_TEMPLATE",            APPPATH."/views/templates/details.src");
      define ("GRID_TEMPLATE",               APPPATH."/views/templates/grid.src");
      define ("NAVIGATOR_TEMPLATE",          APPPATH."/views/templates/navigator.src");

      define ("PHP_SHORT_TAG_OPEN",          "<?");
      define ("PHP_LONG_TAG_OPEN",           "<?php");

      define ("PHP_SHORT_TAG_OPEN_ECHO",     "<?=");
      define ("PHP_LONG_TAG_OPEN_ECHO",      "<?php echo ");

      $this->config->load('application');
      $this->load->helper('text');
//       $this->load->script('codecrafter');
      $this->load->helper('date');

   }

	function index() {
       $this->generate();
	}

   function fetchdbs() {

      $db['hostname'] = $this->input->post('d_host');
      $db['username'] = $this->input->post('d_user');
      $db['password'] = $this->input->post('d_userpass');
      $db['database'] = $this->input->post('d_name');
      $db['dbdriver'] = "mysql";
      $db['dbprefix'] = "";
      $db['pconnect'] = TRUE;
      $db['db_debug'] = false;
      $db['active_r'] = TRUE;

      $result = $this->load->database($db);

      $all_dbs = $this->_list_all_databases();

      echo $this->_draw_db_tree($all_dbs);
   }

   function fetchtabledef() {

      $this->load->helper('form');

      $db['hostname'] = $this->input->post('d_host');
      $db['username'] = $this->input->post('d_user');
      $db['password'] = $this->input->post('d_userpass');
      $db['database'] = $this->input->post('d_name');
      $db['dbdriver'] = "mysql";
      $db['dbprefix'] = "";
      $db['pconnect'] = TRUE;
      $db['db_debug'] = false;
      $db['active_r'] = TRUE;

      $table = $this->input->post('d_table');

      $this->load->database($db);

      $sql = "SHOW COLUMNS FROM " . $table;

      $query = $this->db->query($sql);

      if ($query->num_rows() > 0) {
         $table_markup =  "<table style='width:100%;' cellspacing=0 cellpadding=0>
                           <tr>
                              <th style='background-color:#bdd4eb;border:1px black solid;'>Name</th>
                           <tr>";
         $rowstyle = '';
         foreach ($query->result() as $field) {

            $field_data[] = array( 'name'          => $field->Field,
                     'type'          => $field->Type,
                     'max_length'    => $field->Type,
                     'primary_key'   => $field->Key );

            // If Field is a primary key (and auto increment), suggest no edit
            if ($field->Extra == 'auto_increment') {
               $field_type = 'readonly';
               $field_size = '';
               $field_optionlist = '';
            }
            else {
               // Try and detirmine the form field type from the database type
               if (stristr($field->Type,"enum(")) {
                  // Lose the 'enum' part and the brackets
                  $enumvalues = substr($field->Type,5,-1);
                  $enumoptions = split("','",$enumvalues);
                  $field_optionlist = htmlentities($enumvalues, ENT_QUOTES);
                  $field_size = '';
                  $field_type = 'combobox';
               }
               elseif (stristr($field->Type,"set(")) {
                  // Lose the 'enum' part and the brackets
                  $enumvalues = substr($field->Type,4,-1);
                  $enumoptions = split("','",$enumvalues);
                  $field_optionlist = htmlentities($enumvalues, ENT_QUOTES);
                  $field_size = '';
                  $field_type = 'combobox';
               }

               elseif ( stristr($field->Type,"tinytext") || stristr($field->Type,"mediumtext") || stristr($field->Type,"text") || stristr($field->Type,"longtext") ) {
                  $field_type = 'textarea';
                  $field_optionlist = '';
                  $field_size = '';
               }

               elseif ( stristr($field->Type,"tinyblob") || stristr($field->Type,"mediumblob") || stristr($field->Type,"blob") || stristr($field->Type,"longblob") ) {
                  $field_type = 'textarea';
                  $field_size = '';
                  $field_optionlist = '';
               }
               elseif ( stristr($field->Field,"password") ) {
                  // Catch the off-chance that this will happen
                  $field_type = 'password';
                  $field_size = '20';
                  $field_optionlist = '';
               }
               else {
                  // Catchall is text field
                  $field_type = 'text';
                  $field_size = '20';
                  $field_optionlist = '';
               }

            }

            $options = array(
                  'dontuse'      => 'Ignore',
                  'readonly'     => 'Display Only',
                  'checkbox'     => 'Checkbox',
                  'combobox'     => 'Drop Down',
                  'multiplelist' => 'Multiple Select',
                  'password'     => 'Password',
                  'radiobutton'  => 'Radio Button',
                  'text'         => 'Text',
                  'textarea'     => 'Textarea'
                );

               $field_type_dropdown = form_dropdown("field_type_{$field->Field}", $options, $field_type, "id='field_type_{$field->Field}'  onChange=ProcessFieldType('{$field->Field}');");

               // Get the list of tables and render as a dropdown.
               $tablelist = $this->_list_all_tables($db['database']);

            $fielddefdata['fieldname']             = $field->Field;
            $fielddefdata['fieldtype']             = $field->Type;
            $fielddefdata['field_size']            = $field_size;
            $fielddefdata['field_optionlist']      = $field_optionlist;
            $fielddefdata['field_type_dropdown']   = $field_type_dropdown;
            $fielddefdata['tablelist']             = $tablelist;
            $fielddefdata['table']                 = $table;

            if ($rowstyle == '') {
               $rowstyle='class="alternate"';
            }
            else {
               $rowstyle='';
            }
            $fielddefdata['rowstyle']              = $rowstyle;
            $table_markup .= $this->load->view('fielddef', $fielddefdata, true);

         }
      }
      $table_markup .= '</table>';
      echo $table_markup;

   }

   function fetchtablelist() {

      $db['hostname'] = $this->input->post('d_host');
      $db['username'] = $this->input->post('d_user');
      $db['password'] = $this->input->post('d_userpass');
      $db['database'] = $this->input->post('d_name');
      $db['dbdriver'] = "mysql";
      $db['dbprefix'] = "";
      $db['pconnect'] = TRUE;
      $db['db_debug'] = false;
      $db['active_r'] = TRUE;

      $this->load->database($db);

       echo $this->_draw_table_tree($db['database']);

   }


   function generate() {

      // Show the screen with default values if user is not submitting
      if ( !$this->input->post('generate') ) {
         $defaults['db_host']     = 'mysql.hiperweb.com.br';
         $defaults['db_user']     = 'hiperwe_jornada';
         $defaults['db_password'] = 'jornadaonco';
         // $this->load->view('codecrafter', $defaults);
         $this->load->view('codecrafter_new', $defaults);
         return;
      }
      // else

      // Set up the user database details

      $db['hostname'] = $this->input->post('d_host');
      $db['username'] = $this->input->post('d_user');
      $db['password'] = $this->input->post('d_userpass');
      $db['database'] = $this->input->post('d_name');
      $db['dbdriver'] = "mysql";
      $db['dbprefix'] = "";
      $db['pconnect'] = TRUE;
      $db['db_debug'] = false;
      $db['active_r'] = TRUE;

      // ///////////////////////////////////////////////////////////////////////
      // Get the user options for generating code
      // ///////////////////////////////////////////////////////////////////////
      $selected_table         = $this->input->post('d_table');
      $this->clobber          = $this->input->post('flag_clobber');
      $write_to_disk          = $this->input->post('target_disk');
      $write_to_screen        = $this->input->post('target_screen');

      $build_model            = $this->input->post('build_model');
      $build_controller       = $this->input->post('build_controller');
      $build_view             = $this->input->post('build_view');

      $build_navigator        = $this->input->post('build_navigator');

      $this->grid_type        = $this->input->post('grid_type');     // Pagination

      $this->use_activerecord = $this->input->post('flag_activerecord');

      $this->verbose_mode     = $this->input->post('verbose_mode');

      $this->persistence_mode = $this->input->post('persistence_mode');

      $this->xss_filter_mode  = $this->input->post('xss_filter_mode');

      $this->tag_type         = $this->input->post('tag_type');


      $this->gen_programmer   = $this->config->item('programmer');
      $this->gen_copyright    = $this->config->item('copyright');

      if ( ($write_to_disk == false) && ($write_to_screen == false) ) {
         echo "<SCRIPT>alert('No fair. You must send the output somewhere!');
                  document.location.href = '{$_SERVER['PHP_SELF']}';</SCRIPT>";
         exit;
      }

      echo "Clobber option is $this->clobber <br/>";

      // Connect
      $this->load->database($db);
      // TODO: CI offers no error checking on the load, does it. Therefore, an
      // TODO: ...unsuccessful connection will go undetected until we try and
      // TODO: ...make a request to the database.


      // //////////////////////////////////////////////////////////////////////
      // If no database is providede, then build for all tables in the database.
      // //////////////////////////////////////////////////////////////////////
      if ($selected_table)
      {
         $tables[] = $selected_table;
      }
      else
      {
         // Simple option generates for all tables in selected database.
//         if (function_exists('tables')) {
            $tables = $this->db->tables();
 //        } else {
  //          $tables = $this->db->list_tables();
   //      }


         print_r($tables);
      }

      if ($write_to_disk)
      {

         $this->path_separator = $this->config->item('path_separator');
         $this->suffix         = $this->config->item('suffix');
         $this->output_base    = $this->config->item('output_base');

         $this->_create_output_dir_structure();
      }



      // Create the controller template code

//       $controller_src = file_get_contents(CONTROLLER_TEMPLATE);
//       $model_src      = file_get_contents(MODEL_TEMPLATE);
/*      $details_src    = file_get_contents(DETAILS_TEMPLATE);
      $grid_src       = file_get_contents(GRID_TEMPLATE);*/
      $navigator_src  = file_get_contents(NAVIGATOR_TEMPLATE);

      $template_value = array();
      $actual_value   = array();

      foreach ($tables as $table)
      {
         echo "<hr />Processing table $table<br />";

         // ////////////////////////////////////////////////////////////////////
         // Get some important information about the table being processed
         // ////////////////////////////////////////////////////////////////////
         // Get the tables primary key.
         $primary_key_field = $this->_get_primary_key_field($table);
         echo "DEBUG: primary key for table $table is $primary_key_field<br/>";

         // Get a list of field names to process
         $table_fields = array();

         $table_fields = $this->db->field_names($table);

         // ////////////////////////////////////////////////////////////////////
         // Generate the controller code
         // ////////////////////////////////////////////////////////////////////
         if ($build_controller != false)
         {
            $controller_src = $this->_generate_controller($table, $table_fields, $primary_key_field);

            if ($write_to_screen)
            {
               $output = highlight_code($controller_src);
               echo '<hr /><br />Controller : '.$table.'<br /> <div style=" background-color: #f9f9f9; border: 1px solid #D0D0D0; padding: 12px 10px 12px 10px;">';
               echo $output;
               echo '<br /></div><hr />';
            }

            if ($write_to_disk)
            {
               // Write the controller file
               $controller_file = $this->controllers_dir . $this->path_separator . $table . '.' . $this->suffix;
               $fp = fopen($controller_file,"w");
               fwrite($fp,$controller_src);
               fclose($fp);

               echo "...Writing controller file $controller_file<br/>";
            }
         }

         // ////////////////////////////////////////////////////////////////////
         // Now generate the model code
         // ////////////////////////////////////////////////////////////////////
         if ($build_model != false)
         {

            $model_src = $this->_generate_model($table, $table_fields, $primary_key_field);

            if ($write_to_screen)
            {
               $output = highlight_code($model_src);
               echo "<hr/><br/>Model : $table<br/> <div style=' background-color: #f9f9f9; border: 1px solid #D0D0D0; padding: 12px 10px 12px 10px;'>";
               echo $output;
               echo "<br/></div><hr/>";
            }

            if ($write_to_disk)
            {
               // Write the model file
               $model_file = $this->models_dir . $this->path_separator . $table  . 'model.' . $this->suffix;;
               $fp = fopen($model_file,"w");
               fwrite($fp,$model_src);
               fclose($fp);

               echo "...Writing model file $model_file <br/>";
            }

         }

         if ($build_view != false) {

            // /////////////////////////////////////////////////////////////////
            // Create the views directory for the table, if you need to
            // /////////////////////////////////////////////////////////////////
            if ($write_to_disk) {
               if (!file_exists($this->views_dir . $this->path_separator . $table)) {
                  echo "...Directory $this->views_dir/$this->path_separator/$table does not exist. Creating. ...<br/>";
                  $result = /*$result &&*/ mkdir($this->views_dir . $this->path_separator . $table);       //should add stat check
               }
            }

            // /////////////////////////////////////////////////////////////////
            // Create the grid view for the table
            // /////////////////////////////////////////////////////////////////
            $grid_view_src   = $this->_generate_grid_view($table, $table_fields, $primary_key_field);

            if ($write_to_screen) {
               $output = highlight_code($grid_view_src);
               echo "<hr/><br/>Views Grid: $table<BR> <DIV style=' background-color: #f9f9f9; border: 1px solid #D0D0D0; padding: 12px 10px 12px 10px;'>";
               echo $output;
               echo "<br/></div><hr/>";
            }

            if ($write_to_disk) {

               // Write the Views file
               $view_file = $this->views_dir . $this->path_separator . $table . $this->path_separator . $table  . 'grid.' . $this->suffix;
               $fp = fopen($view_file,"w");
               fwrite($fp,$grid_view_src);
               fclose($fp);

               echo "...Writing table grid view file $view_file <BR>";
            }

            // /////////////////////////////////////////////////////////////////
            // Create the detail view for the table
            // /////////////////////////////////////////////////////////////////
            $detail_view_src = $this->_generate_detail_view($table, $table_fields, $primary_key_field);

            if ($write_to_screen) {
               $output = highlight_code($detail_view_src);
               echo "<hr/><br/>views Detail : $table<br/> <div style=' background-color: #f9f9f9; border: 1px solid #D0D0D0; padding: 12px 10px 12px 10px;'>";
               echo $output;
               echo "<br/></div><hr/>";
            }

            if ($write_to_disk) {


               // Write the model file
               $view_file = $this->views_dir . $this->path_separator . $table . $this->path_separator . $table  . 'details.' . $this->suffix;
               $fp = fopen($view_file,"w");
               fwrite($fp,$detail_view_src);
               fclose($fp);
               echo "...Writing table details view file $view_file <br/>";
            }


         }


         echo "<HR>";
      }

      // ///////////////////////////////////////////////////////////////////////
      // Generate a navigation page if the user requires
      // ///////////////////////////////////////////////////////////////////////
      if ($build_navigator != false) {
         reset($tables);

         $navigator  = "<div class='suckerdiv'>";
         $navigator .= "<ul id='navigator'>";
         foreach($tables as $table) {
//             echo "Table $table";
            $navigator .= "<li>$table
                  <ul>
                     <li><a href='<?= site_url('$table'); ?>'>Browse</a></li>
                     <li><a href='<?= site_url('$table' . '/add/'); ?>'>Add New</a></li>
                     <li><a href='<?= site_url('$table' . '/find/'); ?>'>Find (not yet)</a></li>
                  </ul>
                  </li>";
         }
         $navigator .= "</ul></div>";

         unset($template_value);
         unset($actual_value);

         $template_value[] = '[[navigator_menu]]'  ; $actual_value[] = $navigator;

         $content = str_replace( $template_value, $actual_value , $navigator_src);

         if ($this->tag_type == 'long_tags') {
               // NOTE: We probably shouldn't combine them as it may lead to nasty suprises due
               // ...to the "nested" nature of the tags (<?)=. However, this is ganno lead to some
               // ...extra CPU cycles
               $content = str_replace( PHP_SHORT_TAG_OPEN_ECHO, PHP_LONG_TAG_OPEN_ECHO, $content );
               $content = str_replace( PHP_SHORT_TAG_OPEN,      PHP_LONG_TAG_OPEN, $content );

            }


         if ($write_to_screen) {
            $output = highlight_code($content);
            echo "<hr><br/>CodeCrafter Navigator<br/> <div style=' background-color: #f9f9f9; border: 1px solid #D0D0D0; padding: 12px 10px 12px 10px;'>";
            echo $output;
            echo "<br/></div><hr/>";
         }

         if ($write_to_disk) {
            // Write the Views file
            $navigator_file = $this->views_dir.$this->path_separator.'site'.$this->path_separator.'navigator.' . $this->suffix;

            $fp = fopen($navigator_file,"w");
            fwrite($fp,$content);
            fclose($fp);

            echo "...Writing navigator file stub $navigator_file <br/>";
         }

      }

      // TODO: Why does this only work from the views??
      //echo 'All done in ' . $this->benchmark->elapsed_time();
      if ($write_to_disk) {
         umask( $this->old_umask);
      }
   }


  function _set_array_from_post($table, $fields ) {

      // ///////////////////////////////////////////////////////////////////////
      // TODO: Generate code for persistence model lookup.
      // ///////////////////////////////////////////////////////////////////////

      $src = '';
      if ($this->xss_filter_mode != FALSE)
      {
         $src .= "\t\t".'// XXS Filtering enforced for user input'."\n";
      }
      foreach ($fields as $field)
      {
         if ($this->xss_filter_mode != FALSE)
         {
            if ($this->persistence_mode != FALSE)
            {
               $model_name = $table.'model';
               $src .= "\t\t".'$'.$model_name.'->'.$field."\t\t= \$this->input->post('$field', TRUE);\n";
            }
            else {
               $src .= "\t\t\$data['$field']\t\t= \$this->input->post('$field', TRUE);\n";
            }
         }
         else
         {
            if ($this->persistence_mode != FALSE)
            {
               $model_name = $table.'model';
               $src .= "\t\t".'$'.$model_name.'->'.$field."\t\t= \$this->input->post('$field');\n";
            }
            else {
               $src .= "\t\t\$data['$field']\t\t= \$this->input->post('$field');\n";
            }

         }

      }

      return $src;

  }

  function _build_field_lookups( $fields ) {

      $src = '';
      foreach ($fields as $field) {

         $lookup_field = false;
         $lookup_table = '';
         $lookup_field = '';
         if ( $this->input->post('lookup_' . $field) == 'more' ) {
            $lookup_table       = $this->input->post('lookup_tbl_' . $field);
            $lookup_table_model = $lookup_table . 'model';
//             $lookup_table_list  = $lookup_table . 'list';
            $lookup_field       = $this->input->post('lookup_fld_' . $field);

            $src .= "\t\t// Retrieve the $lookup_table lookup values.\n";
            $src .= "\t\t\$this->load->model('$lookup_table_model');\n";
            $src .= "\t\t\$data['{$lookup_table}list'] = \$this->{$lookup_table_model}->findAll();\n\n";
         }

      }

      return $src;

  }

  function _set_empty_array( $fields ) {

      $src = '';
      foreach ($fields as $field) {
         $src .= "\t\t\$data['$field']\t\t= '';\n";
      }

      return $src;
  }

  function _class_vars($fields) {

      $src = '';
      if ($this->verbose_mode == 'verbose') {
         foreach ($fields as $field) {
            $src .= "var \$$field;\n";
         }
      }

      return $src;

  }

  function _init_class_vars($fields) {

      $src = '';
      if ($this->verbose_mode == 'verbose') {
         foreach ($fields as $field) {
               $src .= "\t\t".'$this->'.$field.' = "";'."\n";
         }
      }

      return $src;

  }

  function _field_get_sets($fields) {

      $src = '';
      if ($this->verbose_mode == 'verbose') {
         foreach ($fields as $field) {
            $func_name = ucfirst($field);
            $src .= "\t".'function get_'.$func_name.'() {'."\n".
                    "\t\t".'return $this->'.$field.';'.
                    "\t".'}'."\n\n";

            $src .= "\t".'function set_'.$func_name.'($'.$field.') {'."\n".
                    "\t\t".'$this->'.$field.' = $'.$field.';'.
                    "\t".'}'."\n\n";

         }

      }

      return $src;

  }

  function _row_from_resultset( $fields ) {

      $src = '';
      if ($this->verbose_mode == 'verbose') {
         foreach ($fields as $field) {
            $src .= "\t\t\t\$query_results['$field']\t\t = \$row['$field'];\n";
         }
         $src .= "\n\t\t\t\$results[]\t\t = \$query_results;\n";
      }
      else {
         $src .= "\t\t\t\$results[]\t\t = \$row;\n";
      }

      return $src;

  }

  function _single_row_from_resultset( $fields ) {

      $src = '';
      if ($this->verbose_mode == 'verbose') {
         foreach ($fields as $field) {
            $src .= "\t\t\$query_results['$field']\t\t = \$row['$field'];\n";
         }
         $src .= "\n\t\t\$results\t\t = \$query_results;\n";
      }
      else {
         $src .= "\t\t\$results\t\t = \$row;\n";
      }

      return $src;

  }


  function _build_form_field($field_name, $field_type, $field_size, $field_options, $lookup_table = false, $lookup_field = false, $lookup_display = false) {

      if ($lookup_table != false) {
         $lookup_tablelist = $lookup_table . 'list';
         $form_field  = '<select name="'.$field_name.'" id="'.$field_name.'" >'."\n";
         $form_field .= "\t\t\t\t".'<option value="">Choose '.ucwords($lookup_table).'</option>';
         $form_field .= '<?'."\n";
         $form_field .= "\t\t\t".' foreach ($'.$lookup_tablelist.' as $'.$lookup_table.') {'."\n";
         $form_field .= "\t\t\t\t".'$lookupid   = $'.$lookup_table.'["'.$lookup_field.'"];'."\n";       // TODO: See line below
         $form_field .= "\t\t\t\t".'$lookuptext   = $'.$lookup_table.'["'.$lookup_display.'"];'."\n";
         $form_field .= "?>\n";
         $form_field .= "\t\t\t\t".'<option value="<?= $lookupid; ?>" <?= ($lookupid == $'.$field_name.')?"selected=selected":""; ?> ><?= $lookuptext; ?></option>'."\n";
         $form_field .= "<?\t\t\t".' } ?>'."\n";
         $form_field .= "\t\t\t".'</select>'."\n";
         return $form_field;
      }

      // else
      switch($field_type) {
         case 'dontuse':
            $form_field = '';
            break;
         case 'readonly':
            $form_field = "<?= \$$field_name; ?>";
            break;
         case 'checkbox':
               $form_field = "<input type='checkbox' name='$field_name' id='$field_name' VALUE='<?= \$$field_name; ?>' />";
            break;
         case 'combobox':
            $option_list = html_entity_decode($field_options, ENT_QUOTES);
            $option_list=str_replace("\\'","'",$option_list);
            $option_list=str_replace("'","",$option_list);
            $options = split(",",$option_list);
            $option_count = count($options);
            $form_field = "<select name='$field_name' id='$field_name' >";
            for ( $i = 0; $i < $option_count; $i++ ) {
               $form_field .="<option value='{$options[$i]}'>{$options[$i]}</option>";
            }
            $form_field .="</select>";
            break;
         case 'multiplelist':
            $option_list = html_entity_decode($field_options, ENT_QUOTES);
            $option_list=str_replace("\\'","'",$option_list);
            $option_list=str_replace("'","",$option_list);
            $options = split(",",$option_list);
            $option_count = count($options);
            $form_field = "<select name='$field_name' ID='$field_name' multiple>";
            for ( $i = 0; $i < $option_count; $i++ ) {
               $form_field .="<option value='{$options[$i]}'>{$options[$i]}</option>";
            }
            $form_field .="</select>";
            break;
         case 'password':
            $form_field = "<input type='password' name='$field_name' id='$field_name' value='<?= \$$field_name; ?>' />";
            break;
         case 'radiobutton':
             $option_list = html_entity_decode($field_options, ENT_QUOTES);
            $option_list=str_replace("\\'","'",$option_list);
            $option_list=str_replace("'","",$option_list);
            $options = split(",",$option_list);
            $option_count = count($options);
            $form_field = '';
            for ( $i = 0; $i < $option_count; $i++ ) {
               $form_field .="<input name='$field_name' id='$field_name' type='radio' value='{$options[$i]}' />";
            }
            break;
         case 'textarea':
            $form_field = "<textarea cols=35 rows=7 NAME='$field_name' id='$field_name' ><?= \$$field_name; ?></textarea>";
            break;
         case 'text':
          default:
            $form_field = "<input type='text' name='$field_name' id='$field_name' value='<?= \$$field_name; ?>' />";
            break;
      }

      return $form_field;

  }

  function _oneformfieldperrow( $fields ) {

      $src = '';

      foreach ($fields as $field) {
         if ( $this->input->post('field_type_' . $field) != false ) {
            //User supplied specs. Use ths
            $field_type   = $this->input->post('field_type_' . $field);
         }
         else {
            $field_type   = 'text';
         }

         if ( $this->input->post('field_size_' . $field) != false ) {
            //User supplied specs. Use ths
            $field_size   = $this->input->post('field_size_' . $field);
         }
         else {
            $field_size   = '20';
         }

         if ( $this->input->post('field_label_' . $field) != false ) {
            //User supplied label. Use ths
            $field_label   = $this->input->post('field_label_' . $field);
         }
         else {
            $field_label   = $field;
         }

         $field_options =  $this->input->post('field_optionlist_' . $field);

         // //////////////////////////////////////////////////////////////////
         // If the field has been specified for relational lookups, then
         // ...display the foriegn key intstead,
         // TODO: For now, we assume all relations are a 1:x, therefore foreign
         // TODO: ...keys are all diplayed in dropdowns.
         // //////////////////////////////////////////////////////////////////
         $lookup_field      = false;
         $lookup_table      = '';
         $lookup_field      = '';
         $lookup_display    = '';

         if ( $this->input->post('lookup_' . $field) == 'more' ) {
            $lookup_table   = $this->input->post('lookup_tbl_' . $field);
            $lookup_field   = $this->input->post('lookup_fld_' . $field);
            $lookup_display = $this->input->post('display_fld_' . $field);

            // Lookup fields are forced to combo fields
            $field_type = 'combobox';
         }

         $form_field = $this->_build_form_field($field, $field_type, $field_size, $field_options, $lookup_table, $lookup_field, $lookup_display );

         $formtxt = "	<tr valign='top' height='20'>\n
            <td align='right'> <b> $field_label:  </b> </td>\n
            <td>
               $form_field
            </td>
         </tr>\n";
         $src .= $formtxt;
      }

      return $src;

   }

   function _get_primary_key_field($table) {
      // Get the table primary key

      $fields = $this->db->field_data($table);

      foreach ($fields as $field) {
         if ($field->primary_key) {
            return $field->name;
         }
      }

      // If we are here. then the table has no primary key.
      return '';

   }

   function _drawgridheader($fields) {

      $src = "\t" . '<th align="right" width="70"> &nbsp; sort by:&nbsp; </th>'."\n";

      foreach ($fields as $field) {
         $field_name = ucfirst($field);
         $src .= "\t<th VALIGN='MIDDLE' ALIGN='CENTER'  class='tbl_headercell'>\n\t\t$field_name\n\t</th>\n";
      }

      return $src;

   }


   function _drawgridbody($table, $fields, $primary_key_field) {

      // Get the table field data

      $fieldcells = '';
      foreach ($fields as $field) {
         $fieldcells .= '   <td align="left" nowrap="nowrap"><?= $'.$table.'[\''.$field.'\']; ?></td>' . "\n";
      }

      // /////////////////////////////////////////////////////////////////////////////
      // Code to generate the grid values. Not the most elegant.
      // /////////////////////////////////////////////////////////////////////////////
      $list_name = "$table".'_list';

      $gridsrc = '
      <?
         $i = 0;
         foreach ($'.$list_name.' as $'.$table.') {
            $i++;
            if (($i%2)==0) { $bgColor = "#FFFFFF"; } else { $bgColor = "#C0C0C0"; }
      ?>
      <tr bgcolor="<?= $bgColor; ?>">
         <td align="center" nowrap="nowrap">
            <a href = "<?= $modify_url."/".$'.$table.'["'.$primary_key_field.'"]; ?>" >Edit</a>
            &nbsp;&nbsp;&nbsp;
            <a href = "<?= $delete_url."/".$'.$table.'["'.$primary_key_field.'"]; ?>" >Delete</a>
         </td>'."\n".
         $fieldcells.
      '</tr>
      <? } ?>';

      $src = $gridsrc;
      return $src;

   }

   // The CI database helper does not provide db meta data. so we are on our own.
   function _list_all_databases() {

      $all_dbs = array();

      $db_list = mysql_list_dbs(/* $link */);
      echo mysql_error();

      while ($row = mysql_fetch_object($db_list)) {
         $all_dbs[] = $row->Database;

      }

      return $all_dbs;
   }

   function _list_all_tables($db) {

      $all_tbls = array();

      $result = mysql_list_tables($db);

      while ($row = mysql_fetch_row($result)) {
//          print_r($row);
         $all_tbls[] = $row[0];
      }
      return $all_tbls;

   }

   function _draw_db_tree($all_dbs) {

      $tree = '';
      $base_url = base_url();
      foreach  ( $all_dbs as $db ) {
         $tree .= "<div id='db_$db' style='width:100%;background:#f9f9e8;'  onMouseOver=\"$('db_$db').style.backgroundColor='#ffffff';\" onMouseOut=\"$('db_$db').style.backgroundColor='#f9f9e8';\" onClick=\"javascript:select_db('$db'); \">\n<img src='$base_url" . "assets/db.gif' height='20' width='25'>$db<br/></div>\n";

      }
      return $tree;
}

   function _draw_table_tree($db) {

      $tree = '';

      // Now build the children by listing all tables for the db;
      $all_tables = $this->_list_all_tables($db);
      $base_url = base_url();
      foreach  ( $all_tables as $table ) {
         //Build level 1 tree
         $tree .= "<div id='tbl_$table' style='width:100%;background:#f9f9e8;' onMouseOver=\"javascript:document.getElementById('tbl_$table').style.backgroundColor='#fff';\" onMouseOut=\"javascript:document.getElementById('tbl_$table').style.backgroundColor='#f9f9e8';\" onClick=\"javascript:select_table('$db', '$table'); \">\n<img src='$base_url" . "assets/table.gif' height='20' width='25'>$table<br/></div>\n";
      }

      return $tree;
   }

   function _get_field_data($table) {

      $sql = "SHOW COLUMNS FROM " . $table;

      $query = $this->db->query($sql);

      if ($query->num_rows() > 0) {
         foreach ($query->result() as $row) {
            print_r($row);
         }
      }

   }


   function fieldlistdropdown() {

      $db['hostname'] = $this->input->post('d_host');
      $db['username'] = $this->input->post('d_user');
      $db['password'] = $this->input->post('d_userpass');
      $db['database'] = $this->input->post('d_name');
      $db['dbdriver'] = "mysql";
      $db['dbprefix'] = "";
      $db['pconnect'] = TRUE;
      $db['db_debug'] = false;
      $db['active_r'] = TRUE;

      $fieldlist_field   = $this->input->post('fieldlist_field');
      $displaylist_field = $this->input->post('displaylist_field');

      $result = $this->load->database($db);

      $table = $this->input->post('d_table');

      $sql = "SHOW COLUMNS FROM " . $table;

      $query = $this->db->query($sql);
      if ($query->num_rows() > 0) {
         $field_data[] = $fieldlist_field . "|" . $displaylist_field;
         foreach ($query->result() as $field) {
            $field_data[] = $field->Field;
         }
         echo join("|",$field_data);
      }
      else {
         echo '';

      }

   }

   function _generate_controller($table, $table_fields, $primary_key_field) {

      $template_value = array();
      $actual_value   = array();

      unset($template_value);
      unset($actual_value);

      // ////////////////////////////////////////////////////////////////////
      // TODO: Process the option to perform pagination
      // ////////////////////////////////////////////////////////////////////

      $template_value[] = '[[creation_date]]';  $actual_value[] = unix_to_human( time() );
      $template_value[] = '[[gen_programmer]]'; $actual_value[] = $this->gen_programmer;
      $template_value[] = '[[gen_copyright]]';  $actual_value[] = $this->gen_copyright;
      $template_value[] = '[[component]]';      $actual_value[] = $table;
      $template_value[] = '[[class]]';          $actual_value[] = ucwords($table);
      $template_value[] = '[[modelname]]';      $actual_value[] = $table.'model';
      $template_value[] = '[[formvalues]]';     $actual_value[] = $this->_set_array_from_post($table, $table_fields);
      $template_value[] = '[[field_lookups]]';  $actual_value[] = $this->_build_field_lookups($table_fields);

      $template_value[] = '[[emptyarray]]';     $actual_value[] = $this->_set_empty_array($table_fields);
      $template_value[] = '[[primary_key_value]]'; $actual_value[] = "\$data['$primary_key_field']";
      $template_value[] = '[[detailsview]]';    $actual_value[] = $table.'details';


      if ($this->use_activerecord == 'transitional_activerecord') {
         $controller_src = file_get_contents(TRANSITIONAL_AR_CONTROLLER_TEMPLATE);
      }
      else {
         $controller_src = file_get_contents(CONTROLLER_TEMPLATE);
      }

      $content = str_replace( $template_value, $actual_value , $controller_src);

      // //////////////////////////////////////////////////////////////////////////////////
      // Force short tage to long if the user wants to
      // //////////////////////////////////////////////////////////////////////////////////
      if ($this->tag_type == 'long_tags') {
         // NOTE: We probably shouldn't combine them as it may lead to nasty suprises due
         // ...to the "nested" nature of the tags (<?)=. However, this is ganno lead to some
         // ...extra CPU cycles
          $content = str_replace( PHP_SHORT_TAG_OPEN_ECHO, PHP_LONG_TAG_OPEN_ECHO, $content );
          $content = str_replace( PHP_SHORT_TAG_OPEN,      PHP_LONG_TAG_OPEN, $content );

      }
      return $content;
   }

   function _generate_model($table, $table_fields, $primary_key_field) {

      $template_value = array();
      $actual_value   = array();

      unset($template_value);
      unset($actual_value);

      $template_value[] = '[[creation_date]]';  $actual_value[] = unix_to_human( time() );
      $template_value[] = '[[gen_programmer]]'; $actual_value[] = $this->gen_programmer;
      $template_value[] = '[[gen_copyright]]';  $actual_value[] = $this->gen_copyright;
      $template_value[] = '[[component]]';      $actual_value[] = $table;
      $template_value[] = '[[class]]';          $actual_value[] = ucwords($table);

      $template_value[] = '[[model_name]]';     $actual_value[] = ucwords($table).'Model';
      $template_value[] = '[[table]]'     ;     $actual_value[] = $table;

      /*         $template_value[] = '[[all_result_set]]'; $actual_value[] = $this->_set_from_resultset( $table_fields );*/

      if ($this->use_activerecord != false) {
         $select_query = '$query = $this->db->get("'.$table.'");';
      }
      else {
         $select_query  = "\t\t".'// Build up the SQL query string'."\n";
         $select_query .= "\t\t\$sql = 'SELECT * FROM $table ' . \$where_clause;\n";
         $select_query .= "\t\t".'$query = $this->db->query($sql);'."\n";


      }
      $template_value[] = '[[select_query]]'; $actual_value[] = $select_query;

      $template_value[] = '[[row_result_set]]'; $actual_value[] = $this->_row_from_resultset( $table_fields );

      $template_value[] = '[[single_row_result_set]]'; $actual_value[] = $this->_single_row_from_resultset( $table_fields );

      $template_value[] = '[[pkey_field]]'; $actual_value[] = $primary_key_field;

      $template_value[] = '[[get_set_functions]]'; $actual_value[] = $this->_field_get_sets($table_fields);

      $template_value[] = '[[class_vars]]'; $actual_value[] = $this->_class_vars($table_fields);

      $template_value[] = '[[init_class_vars]]';
      $actual_value[]   = $this->_init_class_vars($table_fields);

      $template_value[] = '[[empty_class_vars]]';
      $actual_value[]   = $this->_init_class_vars($table_fields);

      if ($this->use_activerecord != false) {
         $model_src      = file_get_contents(ACTIVERECORD_MODEL_TEMPLATE);
      }
      elseif ($this->use_activerecord == 'transitional_activerecord') {
         $model_src      = file_get_contents(TRANSITIONAL_AR_MODEL_TEMPLATE);
      }
      else {
         $model_src      = file_get_contents(MODEL_TEMPLATE);
      }

      $content = str_replace( $template_value, $actual_value , $model_src);

      // //////////////////////////////////////////////////////////////////////////////////
      // Force short tage to long if the user wants to
      // //////////////////////////////////////////////////////////////////////////////////
      if ($this->tag_type == 'long_tags') {
         // NOTE: We probably shouldn't combine them as it may lead to nasty suprises due
         // ...to the "nested" nature of the tags (<?)=. However, this is ganno lead to some
         // ...extra CPU cycles
          $content = str_replace( PHP_SHORT_TAG_OPEN_ECHO, PHP_LONG_TAG_OPEN_ECHO, $content );
          $content = str_replace( PHP_SHORT_TAG_OPEN,      PHP_LONG_TAG_OPEN, $content );
      }

      return $content;
   }

   function _generate_grid_view($table, $table_fields, $primary_key_field) {

      $template_value = array();
      $actual_value   = array();

      // ////////////////////////////////////////////////////////////////////
      // Now generate the Grid Table
      // ////////////////////////////////////////////////////////////////////

      // ///////////////////////////////////////////////////////////////////////
      // NOTE: NOTE: NOTE:
      // Here is where I'm on VERY SHAKY GROUND.
      // The Grid offers the user a chance to select the current record. Now this
      // ...works perfectly when the table has a primary key, but if no such key
      // ...exists, then we are cannot edit the record using a key,
      // ...Instead of guessing, I'm saying that such tables are normally
      // ...complex relationship tables and therefore cannot reliably be edited
      // ...here, hence are omitted from this.
      // ///////////////////////////////////////////////////////////////////////
      if ($primary_key_field == '' ) {
         return '';
      }

      unset($template_value);
      unset($actual_value);

      $template_value[] = '[[component]]'     ; $actual_value[] = $table;
      $template_value[] = '[[gridheaders]]'   ; $actual_value[] = $this->_drawgridheader($table_fields);
      $template_value[] = '[[gridvalues]]'    ; $actual_value[] = $this->_drawgridbody($table,$table_fields,$primary_key_field);

      $template_value[] = '[[action]]'         ; $actual_value[] = 'modify';

      $grid_src       = file_get_contents(GRID_TEMPLATE);
      $content = str_replace( $template_value, $actual_value , $grid_src);

      // //////////////////////////////////////////////////////////////////////////////////
      // Force short tage to long if the user wants to
      // //////////////////////////////////////////////////////////////////////////////////
      if ($this->tag_type == 'long_tags') {
         // NOTE: We probably shouldn't combine them as it may lead to nasty suprises due
         // ...to the "nested" nature of the tags (<?)=. However, this is ganno lead to some
         // ...extra CPU cycles
          $content = str_replace( PHP_SHORT_TAG_OPEN_ECHO, PHP_LONG_TAG_OPEN_ECHO, $content );
          $content = str_replace( PHP_SHORT_TAG_OPEN,      PHP_LONG_TAG_OPEN, $content );

      }

      return $content;

   }

   function _generate_detail_view($table, $table_fields, $primary_key_field) {

      $template_value = array();
      $actual_value   = array();

      // ////////////////////////////////////////////////////////////////////
      // Now generate the Edit/Add form code
      // ////////////////////////////////////////////////////////////////////

      unset($template_value);
      unset($actual_value);

//          $template_value[] = '[[model_name]]'    ; $actual_value[] = ucwords($table).'Model';
      $template_value[] = '[[pkey_field]]'    ; $actual_value[] = $primary_key_field;
      $template_value[] = '[[primary_key_value]]'; $actual_value[] = "<?= \$$primary_key_field; ?>";
      $template_value[] = '[[component]]'     ; $actual_value[] = $table;
      $template_value[] = '[[table]]'         ; $actual_value[] = $table;
      $template_value[] = '[[onefieldperrow]]'; $actual_value[] = $this->_oneformfieldperrow( $table_fields );

      $template_value[] = '[[action]]'         ; $actual_value[] = 'modify';

      $details_src    = file_get_contents(DETAILS_TEMPLATE);
      $content = str_replace( $template_value, $actual_value , $details_src);

      // //////////////////////////////////////////////////////////////////////////////////
      // Force short tage to long if the user wants to
      // //////////////////////////////////////////////////////////////////////////////////
      if ($this->tag_type == 'long_tags') {
         // NOTE: We probably shouldn't combine them as it may lead to nasty suprises due
         // ...to the "nested" nature of the tags (<?)=. However, this is ganno lead to some
         // ...extra CPU cycles
          $content = str_replace( PHP_SHORT_TAG_OPEN_ECHO, PHP_LONG_TAG_OPEN_ECHO, $content );
          $content = str_replace( PHP_SHORT_TAG_OPEN,      PHP_LONG_TAG_OPEN, $content );

      }

      return $content;
   }


   function _create_output_dir_structure() {
/*      if ($write_to_disk)
      {*/
         // Create the output directory structures

         $base_dir = APPPATH . $this->output_base;

         // TODO: This is probably not a good idea to use $this->db->database.
         $database_name = $this->db->database;

         $output_dir = $base_dir . $database_name;
         $this->controllers_dir = $output_dir . $this->path_separator . 'controllers';
         $this->models_dir      = $output_dir . $this->path_separator . 'models';
         $this->views_dir       = $output_dir . $this->path_separator . 'views';
         $this->libraries_dir   = $output_dir . $this->path_separator . 'libraries';

         echo "About to create output directories in $base_dir<br/>";


         // Set the umask and save the current one
         $this->old_umask = umask( 0022);
         $result = true;
         if (!file_exists($base_dir)) {
            echo "...Directory $base_dir does not exist. Creating. ...<br/>";
            $result = $result && mkdir($base_dir);   //should add stat check
         }

         // Don't clobber existing directories
         // TODO: Probably to good idea to allow use to flag clobber dir option
         if (!$this->clobber && file_exists($output_dir) ) {
            show_error('Output directory :<br/><font color="blue">' . $output_dir .
                     '</font><br/>already exists.Cannot continue');
            umask( $this->old_umask );
            exit;
         }
         else {
            // No output dir. Create output directories

            if (!file_exists($output_dir)) {
               echo "...Directory $output_dir does not exist. Creating. ...<br/>";
               $result = $result && mkdir($output_dir);      //should add stat check
            }

            if (!file_exists($this->controllers_dir)) {
               echo "...Directory $this->controllers_dir does not exist. Creating. ...<br/>";
               $result = $result && mkdir($this->controllers_dir); //should add stat check
            }

            if (!file_exists($this->models_dir)) {
               echo "...Directory $this->models_dir does not exist. Creating. ...<br/>";
               $result = $result && mkdir($this->models_dir);      //should add stat check
            }

            if (!file_exists($this->views_dir)) {
               echo "...Directory $this->views_dir does not exist. Creating. ...<br/>";
               $result = $result && mkdir($this->views_dir);       //should add stat check
            }

            if (!file_exists($this->libraries_dir)) {
               echo "...Directory $this->libraries_dir does not exist. Creating. ...<br/>";
               $result = $result && mkdir($this->libraries_dir);   //should add stat check
            }

            if (!file_exists("$this->views_dir/site")) {
               echo "...Directory $this->views_dir/site does not exist. Creating. ...<br/>";
               $result = $result && mkdir("$this->views_dir/site");       //should add stat check
            }


            // Copy the view template files
            echo "... ...Copying layout view files to views directory <BR>";
            @copy( APPPATH . '/views/templates/layout.src',
                  $this->views_dir.$this->path_separator.'site'.$this->path_separator.'layout.php');
            @copy( APPPATH . '/views/templates/header.src',
                  $this->views_dir.$this->path_separator.'site'.$this->path_separator.'header.php');
            @copy( APPPATH . '/views/templates/footer.src',
                  $this->views_dir.$this->path_separator.'site'.$this->path_separator.'footer.php');
            @copy( APPPATH . '/views/templates/main.src',
                  $this->views_dir.$this->path_separator.'site'.$this->path_separator.'main.php');

//             // Copy the layout model
//             @copy( APPPATH . '/views/templates/layoutmodel.src',
//                   $this->models_dir . $this->path_separator  . 'layoutmodel.php');
//             echo "... ...Copying layoutmodel file to models directory <BR>";

            // Copy the appmain file to the controllers dierctory
            @copy( APPPATH . '/views/templates/appmain.src',
                  $this->controllers_dir.$this->path_separator.'appmain.php');

            // Copy the layout library to the libraries dierctory
            @copy( APPPATH . '/views/templates/layout_library.src',
                  $this->libraries_dir. $this->path_separator  . 'Layout.php');
            echo "... ...Copying layout file to libraries directory <br/>";

         }

//       }
   }
}
?>
